#include <iostream>
#include <string>
#include <unistd.h>

using namespace std;
#define NUM 3

volatile bool quit = false;

typedef void (*func_t)(const string&, pthread_mutex_t* mtx, pthread_cond_t* cond); 

void func1(const string& str, pthread_mutex_t* mtx, pthread_cond_t* cond)
{
      while (!quit)
      {
         pthread_mutex_lock(mtx);
         if (!quit)
         pthread_cond_wait(cond, mtx);
         cout << str << " running --a" << endl;
         pthread_mutex_unlock(mtx);
      }     
}

void func2(const string& str, pthread_mutex_t* mtx, pthread_cond_t* cond)
{
      while (!quit)
      {
         pthread_mutex_lock(mtx);
         if (!quit)
         pthread_cond_wait(cond, mtx);
         cout << str << " running --b" << endl;
         pthread_mutex_unlock(mtx);
      }     
}

void func3(const string& str, pthread_mutex_t* mtx, pthread_cond_t* cond)
{
      while (!quit)
      {
         pthread_mutex_lock(mtx);
         if (!quit)
         pthread_cond_wait(cond, mtx);
         cout << str << " running --c" << endl;
         pthread_mutex_unlock(mtx);
      }
}

class thread_Data
{
    public:
    thread_Data(const string& pt_name, func_t fc, pthread_mutex_t* mtx, pthread_cond_t* cond)
    : _pth_name(pt_name), _fc(fc), _mtx(mtx), _cond(cond) 
    {}

   string _pth_name; 
   func_t _fc;
   pthread_mutex_t* _mtx;
   pthread_cond_t* _cond;
};

void* func(void* argc)
{
   thread_Data* tmp = (thread_Data*)argc;
   tmp->_fc(tmp->_pth_name, tmp->_mtx, tmp->_cond);
   delete tmp;
}


int main()
{
   pthread_mutex_t mtx;
   pthread_cond_t cond;
   pthread_mutex_init(&mtx,nullptr);
   pthread_cond_init(&cond,nullptr);

    pthread_t pth[NUM];
    func_t  fun[3] = {func1, func2, func3};
    for (int i = 0; i < NUM; i++)
    {
        string name("thread ");
        name += to_string(i + 1);
        thread_Data* tmp = new thread_Data(name, fun[i], &mtx, &cond);
        pthread_create(pth + i, nullptr, func, (void*)tmp);
    }
   
   int n = 10;
   while (n--)
   {
      cout << "the main signal start running " << endl;
    //  pthread_cond_signal(&cond);
      pthread_cond_broadcast(&cond);
      sleep(1);
   }
   
   quit = true;
   pthread_cond_broadcast(&cond); // 主线程重新唤醒一次，在quit状态改变前进入阻塞的线程，让新线程判断quit一次

    for (int i = 0; i < NUM; i++)
    {
        pthread_join(pth[i], nullptr);
    }

   pthread_mutex_destroy(&mtx);
   pthread_cond_destroy(&cond); 
    return 0;
}





